﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Xml;
using System.Windows.Input;
using System;
using SHomeWorkshop.LunarConcept.Controls;
using SHomeWorkshop.LunarConcept.Adorners;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.ModifingManager;
using SHomeWorkshop.LunarConcept.Enums;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;

namespace SHomeWorkshop.LunarConcept.Widgets
{
    /// <summary>
    /// 创建时间：2012年1月17日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：（贝塞尔）曲线部件。
    /// </summary>
    public class BezierLineWidget : ArrowLineWidget, Interfaces.ICanSameSize, Interfaces.ILinkableLine, Interfaces.ITextRotate
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态构造方法]
        /// </summary>
        static BezierLineWidget()
        {
            dashArray = new DoubleCollection() { 2, 2 };
            contextMenu = (ContextMenu)Globals.MainWindow.MainGrid.FindResource("CMDicBezierLineWidget");
        }

        /// <summary>
        /// [构造方法]
        /// </summary>
        public BezierLineWidget(PageEditor masterEditor)
            : base(masterEditor)
        {
            this.ContextMenu = contextMenu;

            widgetType = Enums.WidgetTypes.BezierLine;
            widgetClassLocalName = Widget.GetWidgetClassLocalName(this.GetType().Name);

            mainPath.Data = new PathGeometry();
            mainPathFigure = new PathFigure() { IsClosed = false };
            (mainPath.Data as PathGeometry).Figures.Add(mainPathFigure);
            mainPathFigure.Segments.Add(mainBezierSegment);

            mainPath.Fill = null;
            mainPath.Stroke = WidgetForeColor;

            mainPath.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(mainPath_PreviewMouseLeftButtonDown);
            mainPath.PreviewMouseRightButtonUp += new MouseButtonEventHandler(mainPath_PreviewMouseRightButtonUp);

            this.mainCanvas.Children.Add(mainPath);

            Canvas.SetZIndex(mainPath, 0);

            #region 两个箭头。
            //startArrowPath.Cursor = Cursors.Arrow;
            startArrowPath.Fill = startArrowPath.Stroke = WidgetForeColor;
            startArrowPath.StrokeThickness = widgetLineWidth;
            PathGeometry startArrowPg = new PathGeometry();
            startArrowPath.Data = startArrowPg;

            startArrowPathFigure.IsClosed = true;
            startArrowPathFigure.IsFilled = true;
            startArrowPathFigure.Segments.Add(startArrowPolyLineSegment);

            startArrowPg.Figures.Add(startArrowPathFigure);

            //endArrowPath.Cursor = Cursors.Arrow;
            endArrowPath.Fill = endArrowPath.Stroke = WidgetForeColor;
            endArrowPath.StrokeThickness = widgetLineWidth;
            PathGeometry endArrowPg = new PathGeometry();
            endArrowPath.Data = endArrowPg;

            endArrowPathFigure.IsClosed = true;
            endArrowPathFigure.IsFilled = true;
            endArrowPathFigure.Segments.Add(endArrowPolyLineSegment);

            endArrowPg.Figures.Add(endArrowPathFigure);

            mainCanvas.Children.Add(startArrowPath);
            mainCanvas.Children.Add(endArrowPath);

            Canvas.SetZIndex(startArrowPath, 1);
            Canvas.SetZIndex(endArrowPath, 1);
            #endregion

            startCPCtrl = new LineCtrlAdorner(this.mainPath, this, Brushes.Salmon) { Visibility = Visibility.Hidden };
            endCPCtrl = new LineCtrlAdorner(this.mainPath, this, Brushes.RoyalBlue) { Visibility = Visibility.Hidden };
            startCtrl = new LineCtrlAdorner(this.mainPath, this, Brushes.Red) { Visibility = Visibility.Hidden };
            endCtrl = new LineCtrlAdorner(this.mainPath, this, Brushes.Blue) { Visibility = Visibility.Hidden };
            startPresentateAdorner = new WidgetPresentateAdorner(this.mainPath, this, Brushes.Red) { Visibility = Visibility.Hidden };
            startPresentateAdorner.PreviewMouseLeftButtonDown += PresentateAdorner_PreviewMouseLeftButtonDown;
            endPresentateAdorner = new WidgetPresentateAdorner(this.mainPath, this, Brushes.Blue) { Visibility = Visibility.Hidden };
            endPresentateAdorner.PreviewMouseLeftButtonDown += PresentateAdorner_PreviewMouseLeftButtonDown;

            startCtrl.ToolTip = endCtrl.ToolTip = StartCPCtrl.ToolTip = endCPCtrl.ToolTip = "双击鼠标左键设置备注文本";

            this.commentAdorner = new CommentAdorner(this.mainPath, this) { Visibility = System.Windows.Visibility.Collapsed };//默认不显示。
            this.commentAdorner.MouseLeftButtonUp += new MouseButtonEventHandler(commentAdorner_MouseLeftButtonUp);

            this.hyperLinkAdorner = new HyperLinkAdorner(this.mainPath, this) { Visibility = System.Windows.Visibility.Collapsed };
            this.hyperLinkAdorner.MouseLeftButtonUp += new MouseButtonEventHandler(hyperLinkAdorner_MouseLeftButtonUp);

            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.mainCanvas);
            if (adornerLayer == null)
            {
                MessageBox.Show("　　未找到Widget的装饰层！", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
            }
            else
            {
                adornerLayer.Add(this.startCPCtrl);
                adornerLayer.Add(this.endCPCtrl);
                adornerLayer.Add(this.startCtrl);
                adornerLayer.Add(this.endCtrl);
                adornerLayer.Add(this.startPresentateAdorner);
                adornerLayer.Add(this.endPresentateAdorner);
                adornerLayer.Add(this.commentAdorner);//这个要在各具体部件类中添加。
                adornerLayer.Add(this.hyperLinkAdorner);//这个要在各具体部件类中添加。
            }

            startCPCtrl.MouseLeftButtonDown += new MouseButtonEventHandler(startCPCtrl_MouseLeftButtonDown);
            endCPCtrl.MouseLeftButtonDown += new MouseButtonEventHandler(endCPCtrl_MouseLeftButtonDown);
            startCtrl.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(startCtrl_MouseLeftButtonDown);
            endCtrl.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(endCtrl_MouseLeftButtonDown);

            startCtrlLine.Stroke = Brushes.Red;
            endCtrlLine.Stroke = Brushes.Blue;

            startCtrlLine.StrokeThickness = 2;
            endCtrlLine.StrokeThickness = 2;

            startCtrlLine.StrokeDashArray = endCtrlLine.StrokeDashArray = dashArray;

            mainCanvas.Children.Add(startCtrlLine);
            mainCanvas.Children.Add(endCtrlLine);

            startArrowPath.MouseLeftButtonDown += new MouseButtonEventHandler(startArrowPath_MouseLeftButtonDown);
            endArrowPath.MouseLeftButtonDown += new MouseButtonEventHandler(endArrowPath_MouseLeftButtonDown);

            //最后添加文本面板。//已移动到基类中。
            //this.mainCanvas.Children.Add(this.mainTextPanel);
            //Canvas.SetZIndex(this.mainTextPanel, 2);

            this.ControlHandlerDoubleClicked += BezierLineWidget_ControlHandlerDoubleClicked;
        }

        private bool isPresentating = false;
        /// <summary>
        /// 是否处于演示状态。
        /// </summary>
        public bool IsPresentating
        {
            get { return isPresentating; }
            set
            {
                isPresentating = value;
                RefreshWidgetLineColor();
            }
        }

        private void PresentateAdorner_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            IsPresentating = !IsPresentating;
            this.IsSelected = false;
            e.Handled = true;
        }

        private void BezierLineWidget_ControlHandlerDoubleClicked(object sender, MouseButtonEventArgs e)
        {
            LunarMessage.Warning(Commands.SetCommentTextCommand.Execute());
        }

        #endregion


        #region 字段与属性===================================================================================================

        private static ContextMenu contextMenu;

        private Point startPoint = new Point(0, 0);
        /// <summary>
        /// [读写]线的起点坐标。
        /// </summary>
        [Tools.LunarProperty("StartPoint", PropertyDateType.Point)]
        public Point StartPoint
        {
            get { return startPoint; }
            set
            {
                startPoint = FormatPoint(value);

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.StartPointTag, startPoint.ToString());
                }

                RefreshLocation();
            }
        }

        private Point endPoint = new Point();
        /// <summary>
        /// [读写]线的终点坐标。
        /// </summary>
        [Tools.LunarProperty("EndPoint", PropertyDateType.Point)]
        public Point EndPoint
        {
            get { return endPoint; }
            set
            {
                endPoint = FormatPoint(value);

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.EndPointTag, endPoint.ToString());
                }

                RefreshLocation();
            }
        }

        private string startMasterId = string.Empty;
        /// <summary>
        /// [读写]首端点挂接的部件的Id。
        /// </summary>
        [Tools.LunarProperty("StartMasterId", PropertyDateType.String)]
        public string StartMasterId
        {
            get { return startMasterId; }
            set
            {
                startMasterId = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.StartMasterIdTag, value);
                }
            }
        }

        private string endMasterId = string.Empty;
        /// <summary>
        /// [读写]尾端点挂接到的部件的Id。
        /// </summary>
        [Tools.LunarProperty("EndMasterId", PropertyDateType.String)]
        public string EndMasterId
        {
            get { return endMasterId; }
            set
            {
                endMasterId = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.EndMasterIdTag, value);
                }
            }
        }

        private ControlDraggingType draggingType = ControlDraggingType.None;
        /// <summary>
        /// [只读]正在拖动哪个控制点。
        /// </summary>
        public ControlDraggingType DraggingType
        {
            get { return draggingType; }
        }

        /// <summary>
        /// [只读]是否被挂接到两个ContentWidget。
        /// </summary>
        public bool IsLinked
        {
            get
            {
                if (startMasterId == string.Empty && endMasterId == string.Empty)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }

        /// <summary>
        /// 连接线永不被设置为锁定。
        /// </summary>
        [Tools.LunarProperty("IsLocked", PropertyDateType.Bool)]
        public override bool IsLocked
        {
            get
            {
                if (IsLinked) return false;

                return base.IsLocked;
            }
            set
            {
                if (IsLinked) return;//连接线不被设置为锁定。

                base.IsLocked = value;
            }
        }

        private BezierLineForms lineForm = BezierLineForms.BezierLine;
        /// <summary>
        /// [读写]画成思维导图线。此属性总是可以设置的，
        /// 但必须在作为连接线时才起作用（以IsLinked为前提）。
        /// </summary>
        [Tools.LunarProperty("LineForm", PropertyDateType.BezierLineForms)]
        public BezierLineForms LineForm
        {
            get { return lineForm; }
            set
            {
                lineForm = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.LineFormTag, value.ToString());
                }

                this.RefreshLineForm();
            }
        }

        public override bool IsSelected
        {
            get { return base.IsSelected; }
            set
            {
                base.IsSelected = value;

                //this.DrawStartSelectedLine(this.startPoint, this.startCPPoint);
                //this.DrawEndSelectedLine(this.endPoint, this.endCPPoint);
            }
        }

        private Path mainPath = new Path() { Cursor = Cursors.Hand };

        public Path MainPath
        {
            get { return mainPath; }
        }

        private PathFigure mainPathFigure;

        public PathFigure MainPathFigure
        {
            get { return mainPathFigure; }
        }

        private BezierSegment mainBezierSegment = new BezierSegment();

        private BezierSegment mindBezierSegement = null;//只有作导图线时才应实例化。

        private LineCtrlAdorner endCPCtrl;

        /// <summary>
        /// CP指ControlPoint
        /// </summary>
        public LineCtrlAdorner EndCPCtrl
        {
            get { return endCPCtrl; }
        }

        private LineCtrlAdorner startCPCtrl;

        /// <summary>
        /// CP指ControlPoint
        /// </summary>
        public LineCtrlAdorner StartCPCtrl
        {
            get { return startCPCtrl; }
        }

        private LineCtrlAdorner startCtrl;

        public LineCtrlAdorner StartCtrl
        {
            get { return startCtrl; }
        }

        private LineCtrlAdorner endCtrl;

        public LineCtrlAdorner EndCtrl
        {
            get { return endCtrl; }
        }

        /// <summary>
        /// 演示时才显示的，用以启动动画来画线。
        /// </summary>
        private WidgetPresentateAdorner startPresentateAdorner;

        /// <summary>
        /// 演示时才显示的，用以启动动画来画线。
        /// </summary>
        public WidgetPresentateAdorner StartPresentateAdorner { get { return startPresentateAdorner; } }

        /// <summary>
        /// 演示时才显示的，用以启动动画来画线。
        /// </summary>
        private WidgetPresentateAdorner endPresentateAdorner;

        /// <summary>
        /// 演示时才显示的，用以启动动画来画线。
        /// </summary>
        public WidgetPresentateAdorner EndPresentateAdorner { get { return endPresentateAdorner; } }

        private Line startCtrlLine = new Line() { Opacity = 0.5 };

        /// <summary>
        /// 首控制线。
        /// </summary>
        public Line StartCtrlLine
        {
            get { return startCtrlLine; }
        }

        private Line endCtrlLine = new Line() { Opacity = 0.5 };

        /// <summary>
        /// 尾控制线。
        /// </summary>
        public Line EndCtrlLine
        {
            get { return endCtrlLine; }
        }

        private Point startCPPoint = new Point();
        [Tools.LunarProperty("StartCPPoint", PropertyDateType.Point)]
        public Point StartCPPoint
        {
            get { return startCPPoint; }
            set
            {
                startCPPoint = FormatPoint(value);

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.StartCPPointTag, startCPPoint.ToString());
                }

                RefreshLocation();
            }
        }

        private Point endCPPoint = new Point();
        [Tools.LunarProperty("EndCPPoint", PropertyDateType.Point)]
        public Point EndCPPoint
        {
            get { return endCPPoint; }
            set
            {
                endCPPoint = FormatPoint(value);

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.EndCPPointTag, endCPPoint.ToString());
                }

                RefreshLocation();
            }
        }


        public override Point BottomRight
        {
            get
            {
                double minLeft, minTop, maxRight, maxBottom;

                minLeft = Math.Min(Math.Min(Math.Min(startPoint.X, endPoint.X), startCPPoint.X), endCPPoint.X);
                maxRight = Math.Max(Math.Max(Math.Max(startPoint.X, endPoint.X), startCPPoint.X), endCPPoint.X);

                minTop = Math.Min(Math.Min(Math.Min(startPoint.Y, endPoint.Y), startCPPoint.Y), endCPPoint.Y);
                maxBottom = Math.Max(Math.Max(Math.Max(startPoint.Y, endPoint.Y), startCPPoint.Y), endCPPoint.Y);

                return new Point(maxRight, maxBottom);
            }
        }

        private double textRotateAngle = 0;
        /// <summary>
        /// [读写]文本旋转角度。取值范围：[-180,180]。
        /// </summary>
        [Tools.LunarProperty("TextRotateAngle", PropertyDateType.Double)]
        public double TextRotateAngle
        {
            get { return textRotateAngle; }
            set
            {
                if (value > 180)
                {
                    textRotateAngle = 180;
                }
                else if (value < -180)
                {
                    textRotateAngle = -180;
                }
                else
                {
                    textRotateAngle = value;
                }

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.TextRotateAngleTag, textRotateAngle.ToString());
                }

                this.RefreshTextRotateAngle();
            }
        }

        public override Point TopLeft
        {
            get
            {
                double minLeft, minTop, maxRight, maxBottom;

                minLeft = Math.Min(Math.Min(Math.Min(startPoint.X, endPoint.X), startCPPoint.X), endCPPoint.X);
                maxRight = Math.Max(Math.Max(Math.Max(startPoint.X, endPoint.X), startCPPoint.X), endCPPoint.X);

                minTop = Math.Min(Math.Min(Math.Min(startPoint.Y, endPoint.Y), startCPPoint.Y), endCPPoint.Y);
                maxBottom = Math.Max(Math.Max(Math.Max(startPoint.Y, endPoint.Y), startCPPoint.Y), endCPPoint.Y);

                return new Point(minLeft, minTop);
            }
        }

        #endregion


        #region 方法=========================================================================================================

        /// <summary>
        /// 根据XmlData内容生成部件内容，设置部件格式。
        /// </summary>
        public override void Build()
        {
            base.Build();

            if (this.xmlData == null) return;

            XmlAttribute attrStartMasterId = this.xmlData.GetAttribute(XmlTags.StartMasterIdTag);
            if (attrStartMasterId != null)
            {
                this.startMasterId = attrStartMasterId.Value;
            }

            XmlAttribute attrEndMasterId = this.xmlData.GetAttribute(XmlTags.EndMasterIdTag);
            if (attrEndMasterId != null)
            {
                this.endMasterId = attrEndMasterId.Value;
            }

            XmlAttribute attrStartPoint = this.xmlData.GetAttribute(XmlTags.StartPointTag);
            if (attrStartPoint != null)
            {
                this.startPoint = FormatPoint(Point.Parse(attrStartPoint.Value));
            }

            XmlAttribute attrStartCPPoint = this.xmlData.GetAttribute(XmlTags.StartCPPointTag);
            if (attrStartCPPoint != null)
            {
                this.startCPPoint = FormatPoint(Point.Parse(attrStartCPPoint.Value));
            }

            XmlAttribute attrEndPoint = this.xmlData.GetAttribute(XmlTags.EndPointTag);
            if (attrEndPoint != null)
            {
                this.endPoint = FormatPoint(Point.Parse(attrEndPoint.Value));
            }

            XmlAttribute attrEndCPPoint = this.xmlData.GetAttribute(XmlTags.EndCPPointTag);
            if (attrEndCPPoint != null)
            {
                this.endCPPoint = FormatPoint(Point.Parse(attrEndCPPoint.Value));
            }

            XmlAttribute attrTextRotateAngle = this.xmlData.GetAttribute(XmlTags.TextRotateAngleTag);
            if (attrTextRotateAngle != null)
            {
                this.textRotateAngle = double.Parse(attrTextRotateAngle.Value);
            }

            XmlAttribute attrLineForm = this.xmlData.GetAttribute(XmlTags.LineFormTag);
            if (attrLineForm != null)
            {
                this.lineForm = (Enums.BezierLineForms)Enum.Parse(typeof(Enums.BezierLineForms), attrLineForm.Value);
            }
            else
            {
                //保持兼容，过去使用这个bool属性。2012年8月12日
                //新枚举中已经考虑到了兼容。
                XmlAttribute attrIsMindMapLine = this.xmlData.GetAttribute(XmlTags.IsMindMapLineTag);
                if (attrIsMindMapLine != null)
                {
                    this.lineForm = (Enums.BezierLineForms)Enum.Parse(typeof(Enums.BezierLineForms), attrIsMindMapLine.Value);
                }
            }

            this.RefreshTextRotateAngle();
            //包含RefreshArrows()调用。
            this.RefreshLocation();

            //此类是下面这几个属性的“最终实现类”。这些属性的值都已在基类确定。因此调用,
            this.RefreshWidgetLineColor();
            this.RefreshWidgetLineWidth();
            this.RefreshLineDash();

        }

        protected override void BuildStyleProperties()
        {
            base.BuildStyleProperties();

            //没有必须在此类读取的、与Style相关的Xml特性
        }

        public override void BuildWidgetStylePropertiesAndRefresh()
        {
            base.BuildWidgetStylePropertiesAndRefresh();

            //此类是下面这几个属性的“最终实现类”。这些属性的值都已在基类确定。因此调用,
            this.RefreshWidgetLineColor();
            this.RefreshWidgetLineWidth();
            this.RefreshLineDash();

            //已在ArrowLineWidget类中调用。
            //this.RefreshWidgetBackColor();
            //this.RefreshArrows();

            //无意义
            //this.RefreshWidgetPadding();

            //这几个在Widget类中已经调用。
            //this.RefreshWidgetForeColor();
            //this.RefreshIsShadowVisible();
            //this.RefreshWidgetOpacity();
        }

        /// <summary>
        /// 根据“IsLinked”的结果分别重绘线条。
        /// </summary>
        public void DrawLine()
        {
            if (masterEditor == null) return;
            if (IsLinked)
            {
                Widget startWidget = masterEditor.GetWidget(this.StartMasterId);
                Widget endWidget = masterEditor.GetWidget(this.EndMasterId);
                if (startWidget == null || endWidget == null)
                {
                    DrawLine(this.startPoint, this.startCPPoint, this.endCPPoint, this.endPoint);
                    return;
                }

                Rect startRect = startWidget.OuterRect;
                Rect endRect = endWidget.OuterRect;
                DrawLine(startRect, this.startCPPoint, this.endCPPoint, endRect);
            }
            else
            {
                DrawLine(this.startPoint, this.startCPPoint, this.endCPPoint, this.endPoint);
            }

            this.RefreshTextPanelLocatin();
        }

        /// <summary>
        /// “IsLinked”为false时，表示此线未连接到ICanLinkedWidget部件。此时由四个点决定线的位置与形状。
        /// </summary>
        /// <param name="startPoint">首端点。</param>
        /// <param name="startCPPoint">首控制点。</param>
        /// <param name="endCPPoint">尾控制点。</param>
        /// <param name="endPoint">尾端点。</param>
        private void DrawLine(Point startPoint, Point startCPPoint, Point endCPPoint, Point endPoint)
        {
            if (this.mindBezierSegement != null &&
                this.mainPathFigure.Segments.Contains(this.mindBezierSegement))
            {
                this.mainPathFigure.Segments.Remove(this.mindBezierSegement);
            }

            this.mainPath.Visibility = Visibility.Visible;
            this.mainPathFigure.IsFilled = this.mainPathFigure.IsClosed = false;

            if (arrows == ArrowType.None)
            {
                mainPathFigure.StartPoint = startPoint;
                mainBezierSegment.Point1 = startCPPoint;
                mainBezierSegment.Point2 = endCPPoint;
                mainBezierSegment.Point3 = endPoint;
            }
            else
            {
                if (arrows == ArrowType.All || arrows == ArrowType.Start)
                {
                    startArrowPathFigure.StartPoint = startPoint;
                    Tools.ArrowPoints apStart = new Tools.ArrowPoints(
                        startArrowPathFigure.StartPoint, startCPPoint, widgetLineWidth * 2);

                    startArrowPolyLineSegment.Points = new PointCollection(){
                    apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
                };
                    mainPathFigure.StartPoint = apStart.ArrowRealTopPoint;
                }
                else
                {
                    mainPathFigure.StartPoint = startPoint;
                }

                mainBezierSegment.Point1 = startCPPoint;
                mainBezierSegment.Point2 = endCPPoint;

                if (arrows == ArrowType.All || arrows == ArrowType.End)
                {
                    endArrowPathFigure.StartPoint = endPoint;
                    Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
                        endArrowPathFigure.StartPoint, endCPPoint, widgetLineWidth * 2);

                    endArrowPolyLineSegment.Points = new PointCollection(){
                    apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                };
                    mainBezierSegment.Point3 = apEnd.ArrowRealTopPoint;
                }
                else
                {
                    mainBezierSegment.Point3 = endPoint;
                }
            }

            //重设首选定线的位置。
            DrawStartSelectedLine(startPoint, startCPPoint);

            //重设尾选定线的位置。
            DrawEndSelectedLine(endPoint, endCPPoint);
        }

        /// <summary>
        /// ★此方法不会调用DrawLine(Point,Point,Point,Point)方法来进行绘制（会重复计算坐标点，效率较低）。
        /// ★应保持此方法与重载版本行为一致！！！
        /// 
        /// “IsLinked”属性为true时，曲线被连接到两个ICanLinkedWidget部件。
        /// 此时，曲线的位置和形状由这两个部件的外框和曲线的两个控制点决定。
        /// 曲线的首端点、尾端点将自动计算，计算的规则是：“首控制点到首矩形的中心点与矩形的交战为首端点”。
        /// </summary>
        /// <param name="startRect">首连接部件外框。</param>
        /// <param name="startCPPoint">首控制点。</param>
        /// <param name="endCPPoint">尾控制点。</param>
        /// <param name="endRect">尾连接部件外框。</param>
        private void DrawLine(Rect startRect, Point startCPPoint, Point endCPPoint, Rect endRect)
        {
            startRect.X -= 4; startRect.Y -= 4; startRect.Height += 8; startRect.Width += 8;
            endRect.X -= 4; endRect.Y -= 4; endRect.Height += 8; endRect.Width += 8;

            if (startRect.IntersectsWith(endRect))
            {
                startCtrl.Visibility =
                    endCtrl.Visibility =
                    startCtrlLine.Visibility =
                    endCtrlLine.Visibility =
                    mainPath.Visibility = Visibility.Hidden;
                return;
            }

            //注意：未连接的曲线，总是不显示为导图线
            if (this.IsLinked == false || this.LineForm == BezierLineForms.BezierLine)
            {
                if (this.isSelected)
                {
                    startCtrl.Visibility = startCPCtrl.Visibility =
                        endCtrl.Visibility = endCPCtrl.Visibility = Visibility.Visible;
                }
                else
                {
                    startCtrl.Visibility = startCPCtrl.Visibility =
                        endCtrl.Visibility = endCPCtrl.Visibility = Visibility.Hidden;
                }

                if (this.mindBezierSegement != null &&
                    this.mainPathFigure.Segments.Contains(this.mindBezierSegement))
                {
                    this.mainPathFigure.Segments.Remove(this.mindBezierSegement);
                }

                mainPath.Visibility = Visibility.Visible;
                this.mainPathFigure.IsFilled = this.mainPathFigure.IsClosed = false;

                this.RefreshArrows(false);
                if (isSelected)
                {
                    startCtrl.Visibility =
                    endCtrl.Visibility =
                    startCtrlLine.Visibility =
                    endCtrlLine.Visibility = Visibility.Visible;
                }

                //边缘留点空白区。
                startRect.X -= 4; startRect.Y -= 4; startRect.Width += 8; startRect.Height += 8;
                endRect.X -= 4; endRect.Y -= 4; endRect.Width += 8; endRect.Height += 8;

                PointToRect.ArrowPoints aptStart = PointToRect.GetCrossPointToRect(startRect, startCPPoint);
                startArrowPathFigure.StartPoint = aptStart.Top;
                Tools.ArrowPoints apStart = new Tools.ArrowPoints(
                    aptStart.Top, startCPPoint, widgetLineWidth * 2);

                startArrowPolyLineSegment.Points = new PointCollection()
                {
                    apStart.ArrowLeftPoint,apStart.ArrowRightPoint,
                };

                mainPathFigure.StartPoint = apStart.ArrowRealTopPoint;

                mainBezierSegment.Point1 = startCPPoint;
                mainBezierSegment.Point2 = endCPPoint;

                PointToRect.ArrowPoints aptEnd = PointToRect.GetCrossPointToRect(endRect, endCPPoint);
                endArrowPathFigure.StartPoint = aptEnd.Top;
                Tools.ArrowPoints apEnd = new Tools.ArrowPoints(
                    aptEnd.Top, endCPPoint, widgetLineWidth * 2);
                endArrowPolyLineSegment.Points = new PointCollection()
                {
                    apEnd.ArrowLeftPoint,apEnd.ArrowRightPoint,
                };
                mainBezierSegment.Point3 = apEnd.ArrowRealTopPoint;

                if (isSelected)
                {
                    DrawStartSelectedLine(aptStart.Top, startCPPoint);
                    DrawEndSelectedLine(aptEnd.Top, endCPPoint);
                }
            }
            else
            {
                //作思维导图线时总是不显示箭头。
                endArrowPath.Visibility =
                    startArrowPath.Visibility = Visibility.Collapsed;

                //作思维导图线时总是不显示两个中控制点和控制线。
                startCPCtrl.Visibility =
                    endCPCtrl.Visibility = Visibility.Collapsed;
                startCtrlLine.Visibility =
                    endCtrlLine.Visibility = Visibility.Collapsed;

                if (startRect.IntersectsWith(endRect))
                {
                    this.mainPath.Visibility = Visibility.Collapsed;
                    return;
                }
                else
                {
                    this.mainPath.Visibility = Visibility.Visible;
                }

                if (this.mindBezierSegement == null)
                {
                    this.mindBezierSegement = new BezierSegment();
                }

                if (this.mainPathFigure.Segments.Contains(this.mindBezierSegement) == false)
                {
                    this.mainPathFigure.Segments.Add(this.mindBezierSegement);//作导图线时，由两个曲线构成。
                }

                //基本思路：
                //根据EndRect.LeftCenter/EndRect.RightCenter/
                //EndRect.TopCenter/EndRect.BottomCenter距离startCenter的长度来决定怎样画法。

                Point tmpStartPoint, tmpStartCPPoint, tmpEndCPPoint, tmpEndPoint;
                ArrowPoints ap = GetMindLinePoints(ref startRect, ref endRect,
                    out tmpStartPoint, out tmpStartCPPoint,
                    out tmpEndCPPoint, out tmpEndPoint);

                this.mainPathFigure.StartPoint = ap.ArrowLeftPoint;
                this.mainBezierSegment.Point1 = tmpStartCPPoint;
                this.mainBezierSegment.Point2 = tmpEndCPPoint;
                this.mainBezierSegment.Point3 = tmpEndPoint;
                this.mindBezierSegement.Point1 = tmpEndCPPoint;
                this.mindBezierSegement.Point2 = tmpStartCPPoint;
                this.mindBezierSegement.Point3 = ap.ArrowRightPoint;

                //刷新文本块位置时要用
                this.startCPPoint = tmpStartCPPoint;
                this.endCPPoint = tmpEndCPPoint;

                this.mainPathFigure.IsFilled = this.mainPathFigure.IsClosed = true;
                this.mainPath.StrokeLineJoin = PenLineJoin.Bevel;
                this.mainPath.Stroke = this.mainPath.Fill = this.widgetLineColor;

                this.startCtrl.CenterPoint = this.startPoint = ap.ArrowTopPoint;
                this.endCtrl.CenterPoint = this.endPoint = tmpEndPoint;

                DrawStartSelectedLine(ap.ArrowRealTopPoint, startCPPoint);
                DrawEndSelectedLine(tmpEndPoint, endCPPoint);

                if (isSelected)
                {
                    startCtrl.Visibility = endCtrl.Visibility = Visibility.Visible;
                    startCPCtrl.Visibility = endCPCtrl.Visibility = Visibility.Hidden;
                }
                else
                {
                    startCtrl.Visibility = startCPCtrl.Visibility =
                        endCtrl.Visibility = endCPCtrl.Visibility = Visibility.Hidden;
                }
            }
        }

        public ArrowPoints GetMindLinePoints(ref Rect startRect, ref Rect endRect,
            out Point tmpStartPoint, out Point tmpStartCPPoint,
            out Point tmpEndCPPoint, out Point tmpEndPoint)
        {
            Point startCenter, endCenter;
            startCenter = new Point(startRect.Left + startRect.Width / 2, startRect.Top + startRect.Height / 2);
            endCenter = new Point(endRect.Left + endRect.Width / 2, endRect.Top + endRect.Height / 2);

            Point endRectLeftCenter = new Point(endRect.Left, endCenter.Y);
            Point endRectRightCenter = new Point(endRect.Right, endCenter.Y);
            Point endRectTopCenter = new Point(endCenter.X, endRect.Top);
            Point endRectBottomCenter = new Point(endCenter.X, endRect.Bottom);

            double lxoffset = Math.Abs(startCenter.X - endRectLeftCenter.X);
            double lyoffset = Math.Abs(startCenter.Y - endRectLeftCenter.Y);
            double leftToStartCenter = Math.Sqrt(lxoffset * lxoffset + lyoffset * lyoffset);

            double rxoffset = Math.Abs(startCenter.X - endRectRightCenter.X);
            double ryoffset = Math.Abs(startCenter.Y - endRectRightCenter.Y);
            double rightToStartCenter = Math.Sqrt(rxoffset * rxoffset + ryoffset * ryoffset);

            double txoffset = Math.Abs(startCenter.X - endRectTopCenter.X);
            double tyoffset = Math.Abs(startCenter.Y - endRectTopCenter.Y);
            double topToStartCenter = Math.Sqrt(txoffset * txoffset + tyoffset * tyoffset);

            double bxoffset = Math.Abs(startCenter.X - endRectBottomCenter.X);
            double byoffset = Math.Abs(startCenter.Y - endRectBottomCenter.Y);
            double bottomToStartCenter = Math.Sqrt(bxoffset * bxoffset + byoffset * byoffset);

            //优先左右。实在没办法才算上下。

            if (endRect.Left > startRect.Right ||       //只要在右侧，不计算距离。
                IsMinLength(leftToStartCenter, rightToStartCenter, topToStartCenter, bottomToStartCenter))
            {
                //在右侧，画向左边中点。

                PointToRect.ArrowPoints ap = Tools.PointToRect.GetCrossPointToRect(startRect, endRectLeftCenter);
                tmpStartCPPoint = tmpEndCPPoint =
                    new Point(endRectLeftCenter.X - Math.Abs(ap.Top.X - endRectLeftCenter.X) / 2, endRectLeftCenter.Y);
                ArrowPoints apStart = ArrowPoints.GetArrowPoints(ap.Top, tmpStartCPPoint, widgetLineWidth);
                tmpStartPoint = apStart.ArrowRealTopPoint;
                tmpEndPoint = endRectLeftCenter;
                return apStart;
            }

            if (endRect.Right < startRect.Left ||       //只要在左侧，不计算距离。
                IsMinLength(rightToStartCenter, leftToStartCenter, topToStartCenter, bottomToStartCenter))
            {
                //在左侧，画向右边中点。

                PointToRect.ArrowPoints ap = Tools.PointToRect.GetCrossPointToRect(startRect, endRectRightCenter);
                tmpStartCPPoint = tmpEndCPPoint =
                    new Point(endRectRightCenter.X + Math.Abs(ap.Top.X - endRectRightCenter.X) / 2, endRectRightCenter.Y);
                ArrowPoints apStart = ArrowPoints.GetArrowPoints(ap.Top, tmpStartCPPoint, widgetLineWidth);
                tmpStartPoint = apStart.ArrowRealTopPoint;
                tmpEndPoint = endRectRightCenter;
                return apStart;
            }

            if (IsMinLength(topToStartCenter, leftToStartCenter, rightToStartCenter, bottomToStartCenter))
            {
                //在下侧，画向顶边中点。

                PointToRect.ArrowPoints ap = Tools.PointToRect.GetCrossPointToRect(startRect, endRectTopCenter);
                tmpStartCPPoint = new Point(ap.Top.X, startRect.Bottom + Math.Abs(endRect.Top - startRect.Bottom) / 3);
                tmpEndCPPoint = new Point(ap.Top.X, endRect.Top - Math.Abs(endRect.Top - startRect.Bottom) / 3);
                ArrowPoints apStart = ArrowPoints.GetArrowPoints(ap.Top, tmpStartCPPoint, widgetLineWidth);
                tmpStartPoint = apStart.ArrowRealTopPoint;
                tmpEndPoint = endRectTopCenter;
                return apStart;
            }

            if (IsMinLength(bottomToStartCenter, topToStartCenter, leftToStartCenter, rightToStartCenter))
            {
                //在上侧，画向底边中点。

                PointToRect.ArrowPoints ap = Tools.PointToRect.GetCrossPointToRect(startRect, endRectBottomCenter);
                tmpStartCPPoint = new Point(ap.Top.X, startRect.Top - Math.Abs(endRect.Bottom - startRect.Top) / 3);
                tmpEndCPPoint = new Point(ap.Top.X, endRect.Bottom + Math.Abs(endRect.Bottom - startRect.Top) / 3);
                ArrowPoints apStart = ArrowPoints.GetArrowPoints(ap.Top, tmpStartCPPoint, widgetLineWidth);
                tmpStartPoint = apStart.ArrowRealTopPoint;
                tmpEndPoint = endRectBottomCenter;
                return apStart;
            }

            tmpStartPoint = tmpStartCPPoint = tmpEndCPPoint = tmpEndPoint = new Point(0, 0);//其实没用处。

            return null;
        }

        /// <summary>
        /// 判断length是否比其它几个参数指定的值都小。
        /// </summary>
        /// <returns></returns>
        private bool IsMinLength(double length, double lengthA, double lengthB, double lengthC)
        {
            if (lengthA < length) return false;
            if (lengthB < length) return false;
            if (lengthC < length) return false;

            return true;
        }

        /// <summary>
        /// 重设被选定时与首端点、首控制点相关的辅助线的位置。
        /// </summary>
        /// <param name="startPoint">首端点。</param>
        /// <param name="startCPPoint">首控制点。</param>
        private void DrawStartSelectedLine(Point startPoint, Point startCPPoint)
        {
            if (masterEditor != null && masterEditor.MasterManager != null)
            {
                startCtrlLine.Stroke = masterEditor.MasterManager.WidgetStartControlerBrush;
            }

            //未连接的总是以曲线显示
            if (this.IsLinked == false || this.LineForm == BezierLineForms.BezierLine)
            {
                if (isSelected)
                {
                    if (IsLinked == false || this.LineForm == BezierLineForms.BezierLine)
                    {
                        if (draggingType == ControlDraggingType.StartCP)
                        {
                            startCtrlLine.Visibility = Visibility.Visible;
                            startCPCtrl.Visibility = Visibility.Hidden;
                        }
                        else
                        {
                            startCtrlLine.Visibility =
                                startCPCtrl.Visibility = Visibility.Visible;
                        }

                        startCtrl.CenterPoint = startPoint;
                        startCtrlLine.X1 = startPoint.X; startCtrlLine.Y1 = startPoint.Y;
                        startCtrlLine.X2 = startCPPoint.X; startCtrlLine.Y2 = startCPPoint.Y;
                        startCtrl.Visibility = System.Windows.Visibility.Visible;
                    }
                    else
                    {
                        startCtrlLine.Visibility =
                            startCPCtrl.Visibility = Visibility.Hidden;
                        startCtrl.Visibility = Visibility.Visible;
                        startCtrl.CenterPoint = startPoint;
                    }
                }
                else
                {
                    startCtrl.Visibility = startCPCtrl.Visibility = System.Windows.Visibility.Hidden;
                }
            }
            else if (this.LineForm == BezierLineForms.MindMapLinkLine)
            {
                startCtrlLine.Visibility = System.Windows.Visibility.Hidden;
                if (isSelected)
                {
                    startCtrl.Visibility = System.Windows.Visibility.Visible;
                    startCPCtrl.Visibility = Visibility.Hidden;
                }
                else
                {
                    startCtrl.Visibility = startCPCtrl.Visibility = System.Windows.Visibility.Hidden;
                }
            }
        }

        /// <summary>
        /// 重设被选定时与尾端点、尾控制点相关的辅助线的位置。
        /// </summary>
        /// <param name="endPoint">尾端点。</param>
        /// <param name="endCPPoint">尾控制点。</param>
        private void DrawEndSelectedLine(Point endPoint, Point endCPPoint)
        {
            if (masterEditor != null && masterEditor.MasterManager != null)
            {
                endCtrlLine.Stroke = masterEditor.MasterManager.WidgetEndControlerBrush;
            }

            //未连接的总是不显示为导图线。
            if (this.IsLinked == false || this.LineForm == BezierLineForms.BezierLine)
            {
                if (isSelected)
                {
                    if (IsLinked == false || this.LineForm == BezierLineForms.BezierLine)
                    {
                        if (draggingType == ControlDraggingType.EndCP)
                        {
                            endCtrlLine.Visibility = Visibility.Visible;//线还是要显示的。
                            endCPCtrl.Visibility = Visibility.Hidden;
                        }
                        else
                        {
                            endCtrlLine.Visibility =
                                endCPCtrl.Visibility = Visibility.Visible;
                        }

                        endCtrl.CenterPoint = endPoint;
                        endCtrlLine.X1 = endPoint.X; endCtrlLine.Y1 = endPoint.Y;
                        endCtrlLine.X2 = endCPPoint.X; endCtrlLine.Y2 = endCPPoint.Y;
                        endCtrl.Visibility = System.Windows.Visibility.Visible;
                    }
                    else
                    {
                        endCtrlLine.Visibility =
                            endCPCtrl.Visibility = Visibility.Hidden;
                        endCtrl.Visibility = Visibility.Visible;
                        endCtrl.CenterPoint = endPoint;
                    }
                }
                else
                {
                    endCtrl.Visibility = endCPCtrl.Visibility = System.Windows.Visibility.Hidden;
                }
            }
            else if (this.LineForm == BezierLineForms.MindMapLinkLine)
            {
                endCtrlLine.Visibility = System.Windows.Visibility.Hidden;
                if (isSelected)
                {
                    endCtrl.Visibility = System.Windows.Visibility.Visible;
                    endCPCtrl.Visibility = Visibility.Hidden;
                }
                else
                {
                    endCtrl.Visibility = endCPCtrl.Visibility = System.Windows.Visibility.Hidden;
                }
            }
        }

        /// <summary>
        /// 重定文本位置。
        /// </summary>
        /// <param name="startPoint">首端点。</param>
        /// <param name="startCPPoint">首控制点。</param>
        /// <param name="endCPPoint">尾控制点。</param>
        /// <param name="endPoint">尾端点。</param>
        private void LocateTextPanel(Point startPoint, Point startCPPoint, Point endCPPoint, Point endPoint)
        {
            switch (this.lineForm)
            {
                case BezierLineForms.MindMapLinkLine:
                    {
                        Canvas.SetLeft(this.mainBorder, this.startCPPoint.X - this.mainBorder.ActualWidth / 2);
                        Canvas.SetTop(this.mainBorder, this.startCPPoint.Y - this.mainBorder.ActualHeight / 2);
                        break;
                    }
                default:
                    {
                        double t = 0.5;

                        //Math.Pow(1 - t, 3) * P0.X + 3 * P1.X * t * Math.Pow(1 - t, 2) + 3 * P2.X * Math.Pow(t, 2) * (1 - t) + P3.X * Math.Pow(0.5, 3)

                        Point center = new Point(
                            Math.Pow(1 - t, 3) * startPoint.X +
                            3 * startCPPoint.X * t * Math.Pow(1 - t, 2) +
                            3 * endCPPoint.X * Math.Pow(t, 2) * (1 - t) + endPoint.X * Math.Pow(0.5, 3),
                            Math.Pow(1 - t, 3) * startPoint.Y +
                            3 * startCPPoint.Y * t * Math.Pow(1 - t, 2) +
                            3 * endCPPoint.Y * Math.Pow(t, 2) * (1 - t) + endPoint.Y * Math.Pow(0.5, 3));

                        Point textStart = new Point(center.X - this.mainBorder.ActualWidth / 2 - this.mainBorder.Margin.Left,
                            center.Y - this.mainBorder.ActualHeight / 2 - this.mainBorder.Margin.Top);

                        Canvas.SetLeft(this.mainBorder, textStart.X);
                        Canvas.SetTop(this.mainBorder, textStart.Y);
                        break;
                    }
            }
        }

        private void LocateTextPanel(Rect startRect, Point startCPPoint, Point endCPPoint, Rect endRect)
        {
            Point startCenter = new Point(startRect.Left + startRect.Width / 2,
                startRect.Top + startRect.Height / 2);
            Point endCenter = new Point(endRect.Left + endRect.Width / 2,
                endRect.Top + endRect.Height / 2);

            Tools.PointToRect.ArrowPoints aptStart = Tools.PointToRect.GetCrossPointToRect(startRect, startCPPoint);
            Tools.PointToRect.ArrowPoints aptEnd = Tools.PointToRect.GetCrossPointToRect(endRect, endCPPoint);

            Point startPoint = aptStart.Top;
            Point endPoint = aptEnd.Top;

            LocateTextPanel(startPoint, startCPPoint, endCPPoint, endPoint);//都不是成员字段。
        }

        void mainPath_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //双击编辑文本
            if (e.ClickCount == 2)
            {
                this.SelectOnlySelf();
                if (Globals.MainWindow.IsPresentatingByPath == false)
                {
                    this.Edit();
                }
                return;
            }

            ModifingItem<Action, ModifingInfo> mi = null;
            ModifingInfo info = null;
            if (FormatSelf(ref mi, ref info))
            {
                if (masterEditor != null)
                {
                    masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.MoveWidgets;
                }
                return;//格式刷格式化，不更改选定状态。
            }

            KeyStates ksRightShift = Keyboard.GetKeyStates(Key.RightShift);
            KeyStates ksLeftShift = Keyboard.GetKeyStates(Key.LeftShift);

            bool isShift = false;

            if ((ksRightShift & KeyStates.Down) > 0 || (ksLeftShift & KeyStates.Down) > 0) { isShift = true; }

            bool isCtrl = false;
            KeyStates ksRightCtrl = Keyboard.GetKeyStates(Key.RightCtrl);
            KeyStates ksLeftCtrl = Keyboard.GetKeyStates(Key.LeftCtrl);

            if ((ksRightCtrl & KeyStates.Down) > 0 || (ksLeftCtrl & KeyStates.Down) > 0) isCtrl = true;

            if (isShift && isCtrl == false)
            {
                //基本规则：
                //    ①如果未选定，选定，并作为活动部件。
                //    ②如果已选定，看是否是活动部件，如果已经是活动部件，整个取消选定状态；
                //                                      如果不是活动部件，设为活动部件。
                if (this.IsSelected == false)
                {
                    this.IsMainSelected = true;
                }
                else
                {
                    if (this.IsMainSelected == false)
                    {
                        this.IsMainSelected = true;
                    }
                    else
                    {
                        this.IsSelected = false;
                    }
                }
            }
            else
            {
                if (this.IsSelected == false)
                {
                    this.SelectOnlySelf();
                }
                //如果是选定的部件，那么可能是在拖动。
            }

            //准备拖动。
            if (masterEditor != null)
            {
                masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.MoveWidgets;
                Point pt = e.GetPosition(this.masterEditor);
                pt = new Point(pt.X - this.masterEditor.BorderThickness.Left, pt.Y - this.masterEditor.BorderThickness.Top);
                masterEditor.MouseInfo.LeftButtonPreviewPoint = pt;
            }
        }

        /// <summary>
        /// 专为右键菜单而准备。选定自身。
        /// </summary>
        void mainPath_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            if (this.IsSelected == false)
            {
                //如果未选定，就作为活动，
                this.SelectOnlySelf();
            }
            else
            {
                //若已选定，不更改选定范围，只更改“活动部件”为此部件
                if (this.IsMainSelected == false) this.IsMainSelected = true;
            }

            if (this.ContextMenu != null)
            {
                this.ContextMenu.IsOpen = true;
            }
        }

        /// <summary>
        /// 放置部件。
        /// </summary>
        public override void DropWidget(ModifingItem<Action, ModifingInfo> mi, Point mousePoint)
        {
            if (mi == null) return;

            Point globalLocation = masterEditor.MouseInfo.LeftButtonPreviewPoint;

            Point newStartPoint = new Point(
                startPoint.X - globalLocation.X + mousePoint.X, startPoint.Y - globalLocation.Y + mousePoint.Y);
            Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag, startPoint.ToString(),
                newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newStartCPPoint = new Point(
                startCPPoint.X - globalLocation.X + mousePoint.X, startCPPoint.Y - globalLocation.Y + mousePoint.Y);
            Action actStartCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartCPPointTag, startCPPoint.ToString(),
                newStartCPPoint.ToString());
            StartCPPoint = newStartCPPoint;

            Point newEndPoint = new Point(
                endPoint.X - globalLocation.X + mousePoint.X, endPoint.Y - globalLocation.Y + mousePoint.Y);
            Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag, endPoint.ToString(),
                newEndPoint.ToString());
            EndPoint = newEndPoint;

            Point newEndCPPoint = new Point(
                endCPPoint.X - globalLocation.X + mousePoint.X, endCPPoint.Y - globalLocation.Y + mousePoint.Y);
            Action actEndCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndCPPointTag, endCPPoint.ToString(),
                newEndCPPoint.ToString());
            EndCPPoint = newEndCPPoint;

            mi.ModifingInfo.NewMainSelectedWidgetID = this.id;
            mi.AddAction(actStartPoint);
            mi.AddAction(actStartCPPoint);
            mi.AddAction(actEndPoint);
            mi.AddAction(actEndCPPoint);

            this.RefreshCommentText();
            this.RefreshHyperLinkText();

            RefreshPresentateAdorners();
        }

        /// <summary>
        /// 放置部件控制点。
        /// </summary>
        public override void DropWidgetControler(Point newMovingPoint, ModifingItem<Action, ModifingInfo> mi)
        {
            if (mi == null || mi.ModifingInfo == null) return;

            ModifingInfo info = mi.ModifingInfo;
            switch (draggingType)
            {
                case ControlDraggingType.Start:
                    {
                        info.ModifingDescription = "拖动曲线首端点";

                        Action actDraggingLineHeader = new Action(masterEditor.Id, id, this.GetType().Name,
                            XmlTags.StartPointTag, startPoint.ToString(), newMovingPoint.ToString());
                        StartPoint = newMovingPoint;
                        info.NewMainSelectedWidgetID = this.id;
                        mi.AddAction(actDraggingLineHeader);
                        break;
                    }
                case ControlDraggingType.StartCP:
                    {
                        info.ModifingDescription = "拖动曲线首控制点";

                        Action actDraggingLineHeader = new Action(masterEditor.Id, id, this.GetType().Name,
                            XmlTags.StartCPPointTag, startCPPoint.ToString(), newMovingPoint.ToString());
                        StartCPPoint = newMovingPoint;

                        info.NewMainSelectedWidgetID = this.id;
                        mi.AddAction(actDraggingLineHeader);

                        //如果是连接线，则还需要更改相应的首端点。
                        if (this.IsLinked)
                        {
                            Widget startMasterWidget = masterEditor.GetWidget(startMasterId);
                            if (startMasterWidget != null)
                            {
                                Rect rect = startMasterWidget.OuterRect;
                                rect.X -= 4; rect.Y -= 4; rect.Width += 8; rect.Height += 8;

                                PointToRect.ArrowPoints apt = PointToRect.GetCrossPointToRect(rect, newMovingPoint);

                                Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name,
                                    XmlTags.StartPointTag, this.StartPoint.ToString(), apt.Top.ToString());
                                this.StartPoint = apt.Top;
                                mi.AddAction(actStartPoint);
                            }
                        }
                        break;
                    }
                case ControlDraggingType.EndCP:
                    {
                        info.ModifingDescription = "拖动曲线尾控制点";

                        Action actDraggingLineHeader = new Action(masterEditor.Id, id, this.GetType().Name,
                            XmlTags.EndCPPointTag, endCPPoint.ToString(), newMovingPoint.ToString());
                        EndCPPoint = newMovingPoint;

                        info.NewMainSelectedWidgetID = this.id;
                        mi.AddAction(actDraggingLineHeader);

                        //如果是连接线，则还需要更改相应的尾端点。
                        if (this.IsLinked)
                        {
                            Widget endMasterWidget = masterEditor.GetWidget(endMasterId);
                            if (endMasterWidget != null)
                            {
                                Rect rect = endMasterWidget.OuterRect;
                                rect.X -= 4; rect.Y -= 4; rect.Width += 8; rect.Height += 8;

                                PointToRect.ArrowPoints apt = PointToRect.GetCrossPointToRect(rect, newMovingPoint);

                                Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name,
                                    XmlTags.EndPointTag, this.EndPoint.ToString(), apt.Top.ToString());
                                this.EndPoint = apt.Top;
                                mi.AddAction(actEndPoint);
                            }
                        }
                        break;
                    }
                case ControlDraggingType.End:
                    {
                        info.ModifingDescription = "拖动曲线尾端点";

                        Action actDraggingLineHeader = new Action(masterEditor.Id, id, this.GetType().Name,
                            XmlTags.EndPointTag, endPoint.ToString(), newMovingPoint.ToString());
                        EndPoint = newMovingPoint;

                        info.NewMainSelectedWidgetID = this.id;
                        mi.AddAction(actDraggingLineHeader);
                        break;
                    }
            }

            this.draggingType = ControlDraggingType.None;//结束拖动。
            DrawStartSelectedLine(this.startPoint, this.startCPPoint);
            DrawEndSelectedLine(this.endPoint, this.endCPPoint);

            this.RefreshCommentText();
            this.RefreshHyperLinkText();

            RefreshPresentateAdorners();
        }

        void endCPCtrl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2)
            {
                OnControlHandlerDoubleClicked(sender, e);
                e.Handled = true;
                return;
            }

            this.SelectOnlySelf();

            //开始拖动。
            e.Handled = true;
            masterEditor.MouseInfo.LeftButtonPreviewPoint = endCPPoint;
            draggingType = ControlDraggingType.EndCP;
            masterEditor.MouseInfo.DraggingType = PageDraggingType.MoveLineWidgetControler;

            endCPCtrl.Visibility = System.Windows.Visibility.Hidden;
        }

        public override void CollapseToTop(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            if (startPoint.Y > endPoint.Y)
            {
                Point newStartPoint = new Point(startPoint.X, startPoint.Y - units);
                Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                    startPoint.ToString(), newStartPoint.ToString());
                StartPoint = newStartPoint;

                mi.AddAction(actStartPoint);
            }
            else if (startPoint.Y < endPoint.Y)
            {
                Point newEndPoint = new Point(endPoint.X, endPoint.Y - units);
                Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                    endPoint.ToString(), newEndPoint.ToString());
                EndPoint = newEndPoint;

                mi.AddAction(actEndPoint);
            }
            //如果水平对齐，则不更改。
        }

        public override void ExpandToBottom(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            if (startPoint.Y > endPoint.Y)
            {
                Point newStartPoint = new Point(startPoint.X, startPoint.Y + units);
                Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                    startPoint.ToString(), newStartPoint.ToString());
                StartPoint = newStartPoint;

                mi.AddAction(actStartPoint);
            }
            else if (startPoint.Y < endPoint.Y)
            {
                Point newEndPoint = new Point(endPoint.X, endPoint.Y + units);
                Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                    endPoint.ToString(), newEndPoint.ToString());
                EndPoint = newEndPoint;

                mi.AddAction(actEndPoint);
            }
            //如果水平对齐，则不更改。
        }

        public override void CollapseToLeft(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            if (startPoint.X > endPoint.X)
            {
                Point newStartPoint = new Point(startPoint.X - units, startPoint.Y);
                Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                    startPoint.ToString(), newStartPoint.ToString());
                StartPoint = newStartPoint;

                mi.AddAction(actStartPoint);
            }
            else if (startPoint.X < endPoint.X)
            {
                Point newEndPoint = new Point(endPoint.X - units, endPoint.Y);
                Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                    endPoint.ToString(), newEndPoint.ToString());
                EndPoint = newEndPoint;

                mi.AddAction(actEndPoint);
            }
            //如果垂直对齐，则不更改
        }

        public override void ExpandToRight(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            if (startPoint.X > endPoint.X)
            {
                Point newStartPoint = new Point(startPoint.X + units, startPoint.Y);
                Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                    startPoint.ToString(), newStartPoint.ToString());
                StartPoint = newStartPoint;

                mi.AddAction(actStartPoint);
            }
            else if (startPoint.X < endPoint.X)
            {
                Point newEndPoint = new Point(endPoint.X + units, endPoint.Y);
                Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                    endPoint.ToString(), newEndPoint.ToString());
                EndPoint = newEndPoint;

                mi.AddAction(actEndPoint);
            }
            //如果垂直对齐，则不更改
        }

        private Point FormatStartMovingPoint(Point newInsideMovingPoint, Point endPoint)
        {
            double horizontalDistance = newInsideMovingPoint.X - endPoint.X;
            double verticalDistance = newInsideMovingPoint.Y - endPoint.Y;

            double absHD = Math.Abs(horizontalDistance);
            double absVD = Math.Abs(verticalDistance);

            if (absVD > absHD)
            {
                if (absVD > absHD * 2)
                {
                    newInsideMovingPoint = new Point(endPoint.X, newInsideMovingPoint.Y);
                }
                else
                {
                    int qua = Getquadrant(newInsideMovingPoint, endPoint);
                    switch (qua)
                    {
                        case 1:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y - (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 2:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y + (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 3:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y - (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 4:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                    endPoint.Y + (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                    }
                }
            }
            else
            {
                if (absVD * 2 < absHD)
                {
                    newInsideMovingPoint = new Point(newInsideMovingPoint.X, endPoint.Y);
                }
                else
                {
                    int qua = Getquadrant(newInsideMovingPoint, endPoint);
                    switch (qua)
                    {
                        case 1:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y - (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 2:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y + (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 3:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                   endPoint.Y - (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                        case 4:
                            {
                                newInsideMovingPoint = new Point(newInsideMovingPoint.X,
                                    endPoint.Y + (newInsideMovingPoint.X - endPoint.X));
                                break;
                            }
                    }
                }
            }

            return newInsideMovingPoint;
        }

        /// <summary>
        /// 以basePoint为基础坐标，画出四象限。
        /// 取出pt在哪个象限中。
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="basePoint"></param>
        /// <returns></returns>
        private int Getquadrant(Point pt, Point basePoint)
        {
            if (pt.X > basePoint.X)
            {
                if (pt.Y > basePoint.Y)
                {
                    return 4;
                }
                else
                {
                    return 1;
                }
            }
            else
            {
                if (pt.Y > basePoint.Y)
                {
                    return 3;
                }
                else
                {
                    return 2;
                }
            }
        }

        public override string GetRelativeOuterXml(Point baseCopyTopLeft)
        {
            if (this.xmlData == null) return string.Empty;

            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X - baseCopyTopLeft.X,
                oldStartPoint.Y - baseCopyTopLeft.Y);
            this.xmlData.SetAttribute(XmlTags.StartPointTag, newStartPoint.ToString());

            Point oldStartCPPoint = startCPPoint;
            Point newStartCPPoint = new Point(oldStartCPPoint.X - baseCopyTopLeft.X,
                oldStartCPPoint.Y - baseCopyTopLeft.Y);
            this.xmlData.SetAttribute(XmlTags.StartCPPointTag, newStartCPPoint.ToString());

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X - baseCopyTopLeft.X,
                oldEndPoint.Y - baseCopyTopLeft.Y);
            this.xmlData.SetAttribute(XmlTags.EndPointTag, newEndPoint.ToString());

            Point oldEndCPPoint = endCPPoint;
            Point newEndCPPoint = new Point(oldEndCPPoint.X - baseCopyTopLeft.X,
                oldEndCPPoint.Y - baseCopyTopLeft.Y);
            this.xmlData.SetAttribute(XmlTags.EndCPPointTag, newEndCPPoint.ToString());

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append(this.xmlData.OuterXml);

            this.xmlData.SetAttribute(XmlTags.StartPointTag, oldStartPoint.ToString());
            this.xmlData.SetAttribute(XmlTags.StartCPPointTag, oldStartCPPoint.ToString());
            this.xmlData.SetAttribute(XmlTags.EndPointTag, oldEndPoint.ToString());
            this.xmlData.SetAttribute(XmlTags.EndCPPointTag, oldEndCPPoint.ToString());
            return sb.ToString();
        }

        void endArrowPath_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            endCtrl_MouseLeftButtonDown(sender, e);
        }

        void startArrowPath_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            startCtrl_MouseLeftButtonDown(sender, e);
        }

        void endCtrl_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2)
            {
                OnControlHandlerDoubleClicked(sender, e);
                e.Handled = true;
                return;
            }

            this.SelectOnlySelf();

            //if (this.IsLinked) return;//连接线需要更改挂接的目标部件。

            //开始拖动。
            e.Handled = true;
            masterEditor.MouseInfo.LeftButtonPreviewPoint = endPoint;
            draggingType = ControlDraggingType.End;
            masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.MoveLineWidgetControler;

            endCtrl.Visibility = System.Windows.Visibility.Hidden;
        }

        void startCtrl_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2)
            {
                OnControlHandlerDoubleClicked(sender, e);
                e.Handled = true;
                return;
            }

            this.SelectOnlySelf();

            //if (this.IsLinked) return;//连接线需要更改挂接的目标部件

            //开始拖动。
            e.Handled = true;
            masterEditor.MouseInfo.LeftButtonPreviewPoint = startPoint;
            draggingType = ControlDraggingType.Start;
            masterEditor.MouseInfo.DraggingType = Enums.PageDraggingType.MoveLineWidgetControler;

            startCtrl.Visibility = System.Windows.Visibility.Hidden;
        }

        /// <summary>
        /// 这个虚方法是用以查看本部件是否在选定框的内部。
        /// 线型部件，各有各的计算办法。
        /// </summary>
        /// <param name="rect"></param>
        /// <returns></returns>
        public override bool IsInRect(Rect rect)
        {
            //return base.IsInRect(rect);//这个要屏蔽。
            bool isInRect = base.IsInRect(rect);
            if (isInRect)
            {
                return true;
            }
            else
            {
                //这个法子还不完善。线是否“穿过”矩形还得另想办法。
                //return rect.Contains(startPoint) || rect.Contains(endPoint) ||
                //    rect.Contains(StartCPPoint) || rect.Contains(EndCPPoint);

                //if (this.IsLinked)//2012年10月15日
                //{
                //只保留这一种
                return rect.Contains(this.startCtrl.CenterPoint) || rect.Contains(this.endCtrl.CenterPoint);
                //}
                //else
                //{
                //}
            }
        }

        public override void MoveUp(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y - units);
            Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newStartCPPoint = new Point(startCPPoint.X, startCPPoint.Y - units);
            Action actStartCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartCPPointTag,
                startCPPoint.ToString(), newStartCPPoint.ToString());
            StartCPPoint = newStartCPPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y - units);
            Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            EndPoint = newEndPoint;

            Point newEndCPPoint = new Point(endCPPoint.X, endCPPoint.Y - units);
            Action actEndCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndCPPointTag,
                endCPPoint.ToString(), newEndCPPoint.ToString());
            EndCPPoint = newEndCPPoint;

            mi.AddAction(actStartPoint);
            mi.AddAction(actStartCPPoint);
            mi.AddAction(actEndPoint);
            mi.AddAction(actEndCPPoint);
        }

        public override void MoveDown(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y + units);
            Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newStartCPPoint = new Point(startCPPoint.X, startCPPoint.Y + units);
            Action actStartCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartCPPointTag,
                startCPPoint.ToString(), newStartCPPoint.ToString());
            StartCPPoint = newStartCPPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y + units);
            Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            EndPoint = newEndPoint;

            Point newEndCPPoint = new Point(endCPPoint.X, endCPPoint.Y + units);
            Action actEndCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndCPPointTag,
                endCPPoint.ToString(), newEndCPPoint.ToString());
            EndCPPoint = newEndCPPoint;

            mi.AddAction(actStartPoint);
            mi.AddAction(actStartCPPoint);
            mi.AddAction(actEndPoint);
            mi.AddAction(actEndCPPoint);
        }

        public override void MoveLeft(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            Point newStartPoint = new Point(startPoint.X - units, startPoint.Y);
            Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newStartCPPoint = new Point(startCPPoint.X - units, startCPPoint.Y);
            Action actStartCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartCPPointTag,
                startCPPoint.ToString(), newStartCPPoint.ToString());
            StartCPPoint = newStartCPPoint;

            Point newEndPoint = new Point(endPoint.X - units, endPoint.Y);
            Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            EndPoint = newEndPoint;

            Point newEndCPPoint = new Point(endCPPoint.X - units, endCPPoint.Y);
            Action actEndCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndCPPointTag,
                endCPPoint.ToString(), newEndCPPoint.ToString());
            EndCPPoint = newEndCPPoint;

            mi.AddAction(actStartPoint);
            mi.AddAction(actStartCPPoint);
            mi.AddAction(actEndPoint);
            mi.AddAction(actEndCPPoint);
        }

        public override void MoveRight(ModifingItem<Action, ModifingInfo> mi, double units = 1)
        {
            if (mi == null) return;

            Point newStartPoint = new Point(startPoint.X + units, startPoint.Y);
            Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            StartPoint = newStartPoint;

            Point newStartCPPoint = new Point(startCPPoint.X + units, startCPPoint.Y);
            Action actStartCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartCPPointTag,
                startCPPoint.ToString(), newStartCPPoint.ToString());
            StartCPPoint = newStartCPPoint;

            Point newEndPoint = new Point(endPoint.X + units, endPoint.Y);
            Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            EndPoint = newEndPoint;

            Point newEndCPPoint = new Point(endCPPoint.X + units, endCPPoint.Y);
            Action actEndCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndCPPointTag,
                endCPPoint.ToString(), newEndCPPoint.ToString());
            EndCPPoint = newEndCPPoint;

            mi.AddAction(actStartPoint);
            mi.AddAction(actStartCPPoint);
            mi.AddAction(actEndPoint);
            mi.AddAction(actEndCPPoint);
        }

        /// <summary>
        /// 改变中心点横坐标。
        /// </summary>
        public override void MoveHorizontalCenterTo(ModifingItem<Action, ModifingInfo> mi, double center)
        {
            if (mi == null || double.IsNaN(center) || masterEditor == null) return;

            double offset = 0;
            double curCenter = TopLeft.X + (BottomRight.X - TopLeft.X) / 2;
            offset = curCenter - center;

            Point newStartPoint = new Point(startPoint.X - offset, startPoint.Y);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newStartCPPoint = new Point(startCPPoint.X - offset, startCPPoint.Y);
            Action actStartCP = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartCPPointTag,
                startCPPoint.ToString(), newStartCPPoint.ToString());
            this.StartCPPoint = newStartCPPoint;

            Point newEndCPPoint = new Point(endCPPoint.X - offset, endCPPoint.Y);
            Action actEndCP = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndCPPointTag,
                endCPPoint.ToString(), newEndCPPoint.ToString());
            this.EndCPPoint = newEndCPPoint;

            Point newEndPoint = new Point(endPoint.X - offset, endPoint.Y);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actStartCP);
            mi.AddAction(actEndCP);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 改变中心点纵坐标。
        /// </summary>
        public override void MoveVerticalCenterTo(ModifingItem<Action, ModifingInfo> mi, double center)
        {
            if (mi == null || double.IsNaN(center) || masterEditor == null) return;

            double offset = 0;
            double curCenter = TopLeft.Y + (BottomRight.Y - TopLeft.Y) / 2;
            offset = curCenter - center;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y - offset);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newStartCPPoint = new Point(startCPPoint.X, startCPPoint.Y - offset);
            Action actStartCP = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartCPPointTag,
                startCPPoint.ToString(), newStartCPPoint.ToString());
            this.StartCPPoint = newStartCPPoint;

            Point newEndCPPoint = new Point(endCPPoint.X, endCPPoint.Y - offset);
            Action actEndCP = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndCPPointTag,
                endCPPoint.ToString(), newEndCPPoint.ToString());
            this.EndCPPoint = newEndCPPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y - offset);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actStartCP);
            mi.AddAction(actEndCP);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 与MoveDown不同，这里是指定向下移动到哪个位置（下边缘到哪个位置）。
        /// </summary>
        public override void MoveBottomSiderTo(ModifingItem<Action, ModifingInfo> mi, double bottom)
        {
            if (mi == null || double.IsNaN(bottom) || masterEditor == null) return;

            double offset = 0;
            double maxBottom = BottomRight.Y;
            offset = maxBottom - bottom;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y - offset);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newStartCPPoint = new Point(startCPPoint.X, startCPPoint.Y - offset);
            Action actStartCP = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartCPPointTag,
                startCPPoint.ToString(), newStartCPPoint.ToString());
            this.StartCPPoint = newStartCPPoint;

            Point newEndCPPoint = new Point(endCPPoint.X, endCPPoint.Y - offset);
            Action actEndCP = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndCPPointTag,
                endCPPoint.ToString(), newEndCPPoint.ToString());
            this.EndCPPoint = newEndCPPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y - offset);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actStartCP);
            mi.AddAction(actEndCP);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 与MoveLeft不同，这里是指定向左移动到哪个位置（左边缘到哪个位置）。
        /// </summary>
        public override void MoveLeftSiderTo(ModifingItem<Action, ModifingInfo> mi, double left)
        {
            if (mi == null || double.IsNaN(left) || masterEditor == null) return;

            double offset = 0;
            double minLeft = TopLeft.X;
            offset = minLeft - left;

            Point newStartPoint = new Point(startPoint.X - offset, startPoint.Y);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newStartCPPoint = new Point(startCPPoint.X - offset, startCPPoint.Y);
            Action actStartCP = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartCPPointTag,
                startCPPoint.ToString(), newStartCPPoint.ToString());
            this.StartCPPoint = newStartCPPoint;

            Point newEndCPPoint = new Point(endCPPoint.X - offset, endCPPoint.Y);
            Action actEndCP = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndCPPointTag,
                endCPPoint.ToString(), newEndCPPoint.ToString());
            this.EndCPPoint = newEndCPPoint;

            Point newEndPoint = new Point(endPoint.X - offset, endPoint.Y);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actStartCP);
            mi.AddAction(actEndCP);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 与MoveRight不同，这里是指定向右移动到哪个位置（右边缘到哪个位置）。
        /// </summary>
        public override void MoveRightSiderTo(ModifingItem<Action, ModifingInfo> mi, double right)
        {
            if (mi == null || double.IsNaN(right) || masterEditor == null) return;

            double offset = 0;
            double maxRight = BottomRight.X;
            offset = maxRight - right;

            Point newStartPoint = new Point(startPoint.X - offset, startPoint.Y);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newStartCPPoint = new Point(startCPPoint.X - offset, startCPPoint.Y);
            Action actStartCP = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartCPPointTag,
                startCPPoint.ToString(), newStartCPPoint.ToString());
            this.StartCPPoint = newStartCPPoint;

            Point newEndCPPoint = new Point(endCPPoint.X - offset, endCPPoint.Y);
            Action actEndCP = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndCPPointTag,
                endCPPoint.ToString(), newEndCPPoint.ToString());
            this.EndCPPoint = newEndCPPoint;

            Point newEndPoint = new Point(endPoint.X - offset, endPoint.Y);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actStartCP);
            mi.AddAction(actEndCP);
            mi.AddAction(actEnd);
        }

        /// <summary>
        /// 与MoveUp不同，这里是指定向上移动到哪个位置（上边缘到哪个位置）。
        /// </summary>
        public override void MoveTopSiderTo(ModifingItem<Action, ModifingInfo> mi, double top)
        {
            if (mi == null || double.IsNaN(top) || masterEditor == null) return;

            double offset = 0;
            double minTop = TopLeft.Y;
            offset = minTop - top;

            Point newStartPoint = new Point(startPoint.X, startPoint.Y - offset);
            Action actStart = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                startPoint.ToString(), newStartPoint.ToString());
            this.StartPoint = newStartPoint;

            Point newStartCPPoint = new Point(startCPPoint.X, startCPPoint.Y - offset);
            Action actStartCP = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartCPPointTag,
                startCPPoint.ToString(), newStartCPPoint.ToString());
            this.StartCPPoint = newStartCPPoint;

            Point newEndCPPoint = new Point(endCPPoint.X, endCPPoint.Y - offset);
            Action actEndCP = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndCPPointTag,
                endCPPoint.ToString(), newEndCPPoint.ToString());
            this.EndCPPoint = newEndCPPoint;

            Point newEndPoint = new Point(endPoint.X, endPoint.Y - offset);
            Action actEnd = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                endPoint.ToString(), newEndPoint.ToString());
            this.EndPoint = newEndPoint;

            mi.AddAction(actStart);
            mi.AddAction(actStartCP);
            mi.AddAction(actEndCP);
            mi.AddAction(actEnd);
        }

        public override void MoveWhenDraggingControler(Point newOutSidePoint)
        {
            if (masterEditor == null) return;
            if (this.IsLinked && this.LineForm == BezierLineForms.MindMapLinkLine) return;

            switch (draggingType)
            {
                case ControlDraggingType.Start:
                    {
                        Point newMovingPoint = newOutSidePoint;

                        //重设贝塞尔曲线位置。
                        DrawLine(newMovingPoint, this.startCPPoint, this.endCPPoint, this.endPoint);

                        //重设文字面板位置。
                        LocateTextPanel(newMovingPoint, startCPPoint, endCPPoint, this.endPoint);
                        break;
                    }
                case ControlDraggingType.StartCP:
                    {
                        Point newMovingPoint = newOutSidePoint;

                        Widget startMasterWidget = masterEditor.GetWidget(startMasterId);
                        Widget endMasterWidget = masterEditor.GetWidget(endMasterId);

                        if (startMasterWidget != null && endMasterWidget != null)//Be Linked
                        {
                            //当曲线作为连接线时，拖动首控制点时，应同步刷新首端点的位置。

                            Rect startRect = startMasterWidget.OuterRect;
                            Rect endRect = endMasterWidget.OuterRect;

                            //重设贝塞尔曲线位置。
                            DrawLine(startRect, newMovingPoint, this.endCPPoint, endRect);

                            //重设文字面板位置。
                            LocateTextPanel(startRect, newMovingPoint, this.endCPPoint, endRect);
                        }
                        else
                        {
                            //重设贝塞尔曲线位置。
                            DrawLine(this.startPoint, newMovingPoint, this.endCPPoint, this.endPoint);

                            //重设文字面板位置。
                            LocateTextPanel(this.startPoint, newMovingPoint, this.endCPPoint, this.endPoint);
                        }
                        break;
                    }
                case ControlDraggingType.End:
                    {
                        #region End
                        Point newMovingPoint = newOutSidePoint;

                        DrawLine(this.startPoint, this.startCPPoint, this.endCPPoint, newMovingPoint);

                        LocateTextPanel(this.startPoint, this.startCPPoint, this.endCPPoint, newMovingPoint);
                        #endregion
                        break;
                    }
                case ControlDraggingType.EndCP:
                    {
                        Point newMovingPoint = newOutSidePoint;

                        Widget startMasterWidget = masterEditor.GetWidget(startMasterId);
                        Widget endMasterWidget = masterEditor.GetWidget(endMasterId);

                        if (startMasterWidget != null && endMasterWidget != null)//Be Linked
                        {
                            Rect startRect = startMasterWidget.OuterRect;
                            Rect endRect = endMasterWidget.OuterRect;

                            //重设贝塞尔曲线位置。
                            DrawLine(startRect, this.startCPPoint, newMovingPoint, endRect);

                            //重设文本面板位置。
                            LocateTextPanel(startRect, this.startCPPoint, newMovingPoint, endRect);
                        }
                        else
                        {
                            //重设贝塞尔曲线位置。
                            DrawLine(this.startPoint, this.startCPPoint, newMovingPoint, this.endPoint);

                            //重设文本面板位置。
                            LocateTextPanel(this.startPoint, this.startCPPoint, newMovingPoint, this.endPoint);
                        }
                        break;
                    }
            }

            this.commentAdorner.Visibility =
                this.hyperLinkAdorner.Visibility = Visibility.Collapsed;
        }

        /// <summary>
        /// 移动挂接的主部件时，与此部件连接的线（就是本类的某个实例）需要自动相应地移动。
        /// </summary>
        /// <param name="tmpStartMasterRect">如果指定了此参数，则startRect应按此参数来移动。</param>
        /// <param name="tmpEndMasterRect">如果指定了此参数，则endRect应按此参数来移动。</param>
        public void MoveWhenDraggingMasterWidget(Rect? tmpStartMasterRect = null, Rect? tmpEndMasterRect = null)
        {
            ICanBeLinkedWidget startMaster = masterEditor.GetWidget(startMasterId) as ICanBeLinkedWidget;
            ICanBeLinkedWidget endMaster = masterEditor.GetWidget(endMasterId) as ICanBeLinkedWidget;
            if (startMaster == null || endMaster == null) return;

            Rect startRect = tmpStartMasterRect.HasValue ? tmpStartMasterRect.Value : startMaster.MovingRect;
            Rect endRect = tmpEndMasterRect.HasValue ? tmpEndMasterRect.Value : endMaster.MovingRect;

            DrawLine(startRect, this.startCPPoint, this.endCPPoint, endRect);

            //刷新箭头显示/隐藏状态。不画线。
            RefreshArrows(false);

            if (this.IsLinked && this.LineForm == BezierLineForms.MindMapLinkLine)
            {
                Point tmpStartPoint, tmpStartCPPoint, tmpEndCPPoint, tmpEndPoint;
                ArrowPoints aptStart = this.GetMindLinePoints(ref startRect, ref endRect,
                    out tmpStartPoint, out tmpStartCPPoint,
                    out tmpEndCPPoint, out tmpEndPoint);

                LocateTextPanel(startRect, tmpStartCPPoint, tmpEndCPPoint, endRect);

                if (isSelected)
                {
                    DrawStartSelectedLine(tmpStartPoint, startCPPoint);
                    DrawEndSelectedLine(tmpEndPoint, endCPPoint);
                }
            }
            else
            {
                LocateTextPanel(startRect, this.startCPPoint, this.endCPPoint, endRect);
            }
        }

        public override void MoveWhenDraggingWidget(Point mousePoint)
        {
            if (this.IsLinked && this.LineForm != BezierLineForms.BezierLine) return;

            Point newMovingPoint = mousePoint;

            Point globalLocation = masterEditor.MouseInfo.LeftButtonPreviewPoint;

            Point tmpStartPoint = new Point(startPoint.X - globalLocation.X + newMovingPoint.X,
                startPoint.Y - globalLocation.Y + newMovingPoint.Y);
            Point tmpEndPoint = new Point(endPoint.X - globalLocation.X + newMovingPoint.X,
                endPoint.Y - globalLocation.Y + newMovingPoint.Y);
            Point tmpStartCPPoint = new Point(startCPPoint.X - globalLocation.X + newMovingPoint.X,
                startCPPoint.Y - globalLocation.Y + newMovingPoint.Y);
            Point tmpEndCPPoint = new Point(endCPPoint.X - globalLocation.X + newMovingPoint.X,
                endCPPoint.Y - globalLocation.Y + newMovingPoint.Y);

            //重设贝塞尔曲线位置。
            DrawLine(tmpStartPoint, tmpStartCPPoint, tmpEndCPPoint, tmpEndPoint);

            startCtrl.CenterPoint = tmpStartPoint;
            endCtrl.CenterPoint = tmpEndPoint;
            startCPCtrl.CenterPoint = tmpStartCPPoint;
            endCPCtrl.CenterPoint = tmpEndCPPoint;

            startCtrlLine.X1 = tmpStartPoint.X; startCtrlLine.X2 = tmpStartCPPoint.X;
            startCtrlLine.Y1 = tmpStartPoint.Y; startCtrlLine.Y2 = tmpStartCPPoint.Y;

            endCtrlLine.X1 = tmpEndPoint.X; endCtrlLine.X2 = tmpEndCPPoint.X;
            endCtrlLine.Y1 = tmpEndPoint.Y; endCtrlLine.Y2 = tmpEndCPPoint.Y;

            //重设文本面板位置。
            LocateTextPanel(tmpStartPoint, tmpStartCPPoint, tmpEndCPPoint, tmpEndPoint);

            this.commentAdorner.Visibility =
                this.hyperLinkAdorner.Visibility = Visibility.Collapsed;
        }

        /// <summary>
        /// 刷新箭头状态。
        /// </summary>
        public override void RefreshArrows()
        {
            this.RefreshArrows(true);
        }

        /// <summary>
        /// 刷新箭头状态。
        /// </summary>
        /// <param name="drawLine">若为真，按已设置的startPoint/startCPpoint/endCPPoint/endPoint画线及箭头。</param>
        private void RefreshArrows(bool drawLine)
        {
            base.RefreshArrows();

            if (drawLine) DrawLine();

            if (this.IsLinked && this.LineForm == BezierLineForms.MindMapLinkLine)
            {
                this.endArrowPath.Visibility = this.startArrowPath.Visibility =
                    Visibility.Collapsed;//作导图线时总是隐藏箭头。
            }
        }

        /// <summary>
        /// 刷新所有控制点。
        /// </summary>
        public override void RefreshControlers()
        {
            if (isSelected)
            {
                //刷新控制点色彩
                if (masterEditor != null && masterEditor.MasterManager != null)
                {
                    if (startCtrl.MainSelectedBrush != masterEditor.MasterManager.WidgetStartControlerBrush)
                        startCtrl.MainSelectedBrush = masterEditor.MasterManager.WidgetStartControlerBrush;
                    if (startCPCtrl.MainSelectedBrush != masterEditor.MasterManager.WidgetStartControlerBrush)
                        startCPCtrl.MainSelectedBrush = masterEditor.MasterManager.WidgetStartControlerBrush;
                    if (startCtrlLine.Fill != masterEditor.MasterManager.WidgetStartControlerBrush)
                        startCtrlLine.Fill = masterEditor.MasterManager.WidgetStartControlerBrush;

                    if (endCPCtrl.MainSelectedBrush != masterEditor.MasterManager.WidgetEndControlerBrush)
                        endCPCtrl.MainSelectedBrush = masterEditor.MasterManager.WidgetEndControlerBrush;
                    if (endCtrl.MainSelectedBrush != masterEditor.MasterManager.WidgetEndControlerBrush)
                        endCtrl.MainSelectedBrush = masterEditor.MasterManager.WidgetEndControlerBrush;
                    if (endCtrlLine.Fill != masterEditor.MasterManager.WidgetEndControlerBrush)
                        endCtrlLine.Fill = masterEditor.MasterManager.WidgetEndControlerBrush;
                }

                startCPCtrl.CenterPoint = startCPPoint;
                endCPCtrl.CenterPoint = endCPPoint;

                #region 改由DrawLine()方法控制，因支持不同形态线条，要求的控制点不同。
                //startCtrl.CenterPoint = startPoint;                
                //endCtrl.CenterPoint = endPoint; 
                #endregion

                DrawStartSelectedLine(startPoint, startCPPoint);
                DrawEndSelectedLine(endPoint, endCPPoint);

                startCtrl.Visibility =
                    endCtrl.Visibility = System.Windows.Visibility.Visible;

                if (this.IsLinked && this.LineForm == BezierLineForms.MindMapLinkLine)
                {
                    startCtrlLine.Visibility = endCtrlLine.Visibility =
                        startCPCtrl.Visibility = endCPCtrl.Visibility = System.Windows.Visibility.Collapsed;
                }
                else
                {
                    startCtrlLine.Visibility = endCtrlLine.Visibility =
                        startCPCtrl.Visibility = endCPCtrl.Visibility = System.Windows.Visibility.Visible;
                }
            }
            else
            {
                startCtrlLine.Visibility = endCtrlLine.Visibility =
                startCtrl.Visibility = startCPCtrl.Visibility = endCPCtrl.Visibility =
                    endCtrl.Visibility = System.Windows.Visibility.Hidden;
            }
        }

        public override void RefreshLineDash()
        {
            switch (lineDash)
            {
                case LineDashType.DashType.Dash:
                    {
                        this.mainPath.StrokeDashArray = LineDashType.dashCollection; break;
                    }
                case LineDashType.DashType.DashDotDot:
                    {
                        this.mainPath.StrokeDashArray = LineDashType.dashDotDotCollection; break;
                    }
                case LineDashType.DashType.Dot:
                    {
                        this.mainPath.StrokeDashArray = LineDashType.dotCollection; break;
                    }
                case LineDashType.DashType.Solid:
                    {
                        this.mainPath.StrokeDashArray = LineDashType.solidCollection; break;
                    }
                default:
                    {
                        this.mainPath.StrokeDashArray = LineDashType.dashDotCollection; break;
                    }
            }
        }

        public void RefreshLineForm()
        {
            this.DrawLine();
            //this.RefreshTextPanelLocatin();//this.DrawLine()末尾会自动调用。
        }

        public override void RefreshIsSelected()
        {
            base.RefreshIsSelected();

            if (startMasterId != string.Empty)
            {
                startCtrl.Form = LineCtrlAdorner.ControlerType.Rectangle;
            }
            else
            {
                startCtrl.Form = LineCtrlAdorner.ControlerType.Ellipse;
            }

            if (endMasterId != string.Empty)
            {
                endCtrl.Form = LineCtrlAdorner.ControlerType.Rectangle;
            }
            else
            {
                endCtrl.Form = LineCtrlAdorner.ControlerType.Ellipse;
            }

            this.DrawStartSelectedLine(this.startPoint, this.startCPPoint);
            this.DrawEndSelectedLine(this.endPoint, this.endCPPoint);
        }

        /// <summary>
        /// 刷新线宽。
        /// </summary>
        public override void RefreshWidgetLineWidth()
        {
            base.RefreshWidgetLineWidth();

            //强制曲线跳过宽度１（当作２看待）——因为会模糊，很难看。
            //mainPath.StrokeThickness = (lineWidth < 2 ? 2 : lineWidth);

            double newLineWidth = (widgetLineWidth < 1 ? 1 : widgetLineWidth);
            mainPath.StrokeThickness = newLineWidth;//还是支持宽度1的线为妙。

            //if (widgetLineWidth == 1)
            //{
            //    RenderOptions.SetEdgeMode(mainPath, EdgeMode.Aliased);
            //}
            //else
            //{
            //    RenderOptions.SetEdgeMode(mainPath, EdgeMode.Unspecified);
            //}

            startArrowPath.StrokeThickness = endArrowPath.StrokeThickness = newLineWidth;
        }

        public override void RefreshLocation()
        {
            base.RefreshLocation();

            DrawLine();

            //mainPathFigure.StartPoint = startPoint;
            //mainBezierSegment.Point1 = startCPPoint;
            //mainBezierSegment.Point2 = endCPPoint;
            //mainBezierSegment.Point3 = endPoint;

            RefreshWidgetLineWidth();
            RefreshArrows();
            RefreshControlers();

            this.RefreshTextRotateAngle();
            RefreshPresentateAdorners();
        }

        public void RefreshPresentateAdorners()
        {
            if (Globals.MainWindow.rtbtnAutoHideBazeirLine.IsChecked == true && Globals.MainWindow.IsPresentatingByPath)
            {
                this.startPresentateAdorner.Visibility = this.endPresentateAdorner.Visibility = Visibility.Visible;
                this.startPresentateAdorner.InvalidateVisual();
                this.endPresentateAdorner.InvalidateVisual();
            }
            else
            {
                this.startPresentateAdorner.Visibility = this.endPresentateAdorner.Visibility = Visibility.Hidden;
            }
        }

        public override void RefreshPointWhenGroupIn(Point baseTopLeft)
        {
            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X - baseTopLeft.X,
                oldStartPoint.Y - baseTopLeft.Y);
            StartPoint = newStartPoint;

            Point oldStartCPPoint = startCPPoint;
            Point newStartCPPoint = new Point(oldStartCPPoint.X - baseTopLeft.X,
                oldStartCPPoint.Y - baseTopLeft.Y);
            StartCPPoint = newStartCPPoint;

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X - baseTopLeft.X,
                oldEndPoint.Y - baseTopLeft.Y);
            EndPoint = newEndPoint;

            Point oldEndCPPoint = endCPPoint;
            Point newEndCPPoint = new Point(oldEndCPPoint.X - baseTopLeft.X,
                oldEndCPPoint.Y - baseTopLeft.Y);
            EndCPPoint = newEndCPPoint;
        }

        public override void RefreshPointWhenGroupOut(Point baseTopLeft)
        {
            Point oldStartPoint = startPoint;
            Point newStartPoint = new Point(oldStartPoint.X + baseTopLeft.X,
                oldStartPoint.Y + baseTopLeft.Y);
            StartPoint = newStartPoint;

            Point oldStartCPPoint = startCPPoint;
            Point newStartCPPoint = new Point(oldStartCPPoint.X + baseTopLeft.X,
                oldStartCPPoint.Y + baseTopLeft.Y);
            StartCPPoint = newStartCPPoint;

            Point oldEndPoint = endPoint;
            Point newEndPoint = new Point(oldEndPoint.X + baseTopLeft.X,
                oldEndPoint.Y + baseTopLeft.Y);
            EndPoint = newEndPoint;

            Point oldEndCPPoint = endCPPoint;
            Point newEndCPPoint = new Point(oldEndCPPoint.X + baseTopLeft.X,
                oldEndCPPoint.Y + baseTopLeft.Y);
            EndCPPoint = newEndCPPoint;
        }

        public override void RefreshWidgetLineColor()
        {
            if (Globals.MainWindow.rtbtnAutoHideBazeirLine.IsChecked == true && Globals.MainWindow.IsPresentatingByPath)
            {
                if (IsPresentating)
                {
                    this.startArrowPath.Fill =
                        this.startArrowPath.Stroke =
                        this.endArrowPath.Fill =
                        this.endArrowPath.Stroke =
                        this.mainPath.Stroke = Brushes.Transparent;

                    if (this.LineForm == BezierLineForms.MindMapLinkLine)
                    {
                        this.mainPath.Fill = Brushes.Transparent;
                    }
                }
                else
                {
                    this.startArrowPath.Fill =
                        this.startArrowPath.Stroke =
                        this.endArrowPath.Fill =
                        this.endArrowPath.Stroke =
                        this.mainPath.Stroke = this.widgetLineColor;

                    if (this.LineForm == BezierLineForms.MindMapLinkLine)
                    {
                        this.mainPath.Fill = this.widgetLineColor;
                    }
                }
            }
            else
            {

                startArrowPath.Stroke = endArrowPath.Stroke =
                    startArrowPath.Fill = endArrowPath.Fill =
                        mainPath.Stroke = mainPath.Fill = WidgetLineColor;
            }
        }

        protected void RefreshSelectedStatus()
        {
            //base.RefreshSelectedStatus();
            RefreshControlers();
        }

        public override void RefreshIsShadowVisible()
        {
            base.RefreshIsShadowVisible();

            if (isShadowVisible)
            {
                this.mainPath.Effect = Widget.ShadowEffect;
            }
            else
            {
                this.mainPath.Effect = null;
            }
        }

        public override void RefreshTextPanelLocatin()
        {
            LocateTextPanel(this.startPoint, this.startCPPoint, this.endCPPoint, this.endPoint);
        }

        /// <summary>
        /// 刷新文本区旋转角度。
        /// </summary>
        public void RefreshTextRotateAngle()
        {
            if (this.mainTextPanel.RenderTransformOrigin != DefaultRenderCenter)
            {
                this.mainTextPanel.RenderTransformOrigin = DefaultRenderCenter;
            }

            if (this.textRotateAngle == 0)
            {
                this.mainTextPanel.RenderTransform = DefaultRotateTransform;
            }
            else
            {
                this.mainTextPanel.RenderTransform = new RotateTransform(textRotateAngle);
            }
        }

        /// <summary>
        /// 重置两个控制点（主要用于控制点拖得太长，超出边界后找不到的情况）。
        /// </summary>
        /// <param name="mi">修改操作记录条目。</param>
        public void ResetControlers(ModifingItem<Action, ModifingInfo> mi)
        {
            if (mi == null || mi.ModifingInfo == null)
            {
                MessageBox.Show("　　BezierLineWidget的ResetControlers()方法的mi参数或mi.ModifingInfo参数不能为null。",
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            if (masterEditor == null || masterEditor.MasterManager == null) return;

            mi.ModifingInfo.ModifingDescription = "复位控制点";

            if (this.IsLinked && this.LineForm == BezierLineForms.MindMapLinkLine)
            {
                Point tmpStartPoint, tmpStartCPPoint, tmpEndCPPoint, tmpEndPoint;
                Widget startMaster = this.MasterEditor.GetWidget(this.startMasterId);
                Widget endMaster = this.MasterEditor.GetWidget(this.endMasterId);
                if (startMaster == null || endMaster == null) return;
                Rect startRect = startMaster.OuterRect;
                Rect endRect = endMaster.OuterRect;
                ArrowPoints aptStart = this.GetMindLinePoints(ref startRect, ref endRect,
                    out tmpStartPoint, out tmpStartCPPoint,
                    out tmpEndCPPoint, out tmpEndPoint);

                Point newStartCPPoint = tmpStartCPPoint;
                Point newEndCPPoint = tmpEndCPPoint;

                Action actStartPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartPointTag,
                    StartPoint.ToString(), tmpStartPoint.ToString());
                StartPoint = tmpStartPoint;

                Action actStartCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartCPPointTag,
                    startCPPoint.ToString(), tmpStartCPPoint.ToString());
                StartCPPoint = tmpStartCPPoint;

                Action actEndCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndCPPointTag,
                    endCPPoint.ToString(), tmpEndCPPoint.ToString());
                EndCPPoint = tmpEndCPPoint;


                Action actEndPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndPointTag,
                    EndPoint.ToString(), tmpEndPoint.ToString());
                EndPoint = tmpEndPoint;

                mi.AddAction(actStartPoint);
                mi.AddAction(actStartCPPoint);
                mi.AddAction(actEndCPPoint);
                mi.AddAction(actEndPoint);
            }
            else
            {

                Point newStartCPPoint = new Point(startPoint.X + (endPoint.X - startPoint.X) / 3,
                    startPoint.Y + (endPoint.Y - startPoint.Y) / 3);
                Point newEndCPPoint = new Point(endPoint.X - (endPoint.X - startPoint.X) / 3,
                    endPoint.Y - (endPoint.Y - startPoint.Y) / 3);

                Action actStartCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.StartCPPointTag,
                    startCPPoint.ToString(), newStartCPPoint.ToString());

                StartCPPoint = newStartCPPoint;

                Action actEndCPPoint = new Action(masterEditor.Id, id, this.GetType().Name, XmlTags.EndCPPointTag,
                    endCPPoint.ToString(), newEndCPPoint.ToString());

                EndCPPoint = newEndCPPoint;
                mi.AddAction(actStartCPPoint);
                mi.AddAction(actEndCPPoint);
            }

            masterEditor.MasterManager.RegisterModifingItem(mi);
        }

        public event EventHandler<MouseButtonEventArgs> ControlHandlerDoubleClicked;

        protected void OnControlHandlerDoubleClicked(object sender, MouseButtonEventArgs e)
        {
            if (ControlHandlerDoubleClicked != null)
            {
                ControlHandlerDoubleClicked(sender, e);
            }
        }

        void startCPCtrl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2)
            {
                OnControlHandlerDoubleClicked(sender, e);
                e.Handled = true;
                return;
            }

            this.SelectOnlySelf();

            //开始拖动。
            e.Handled = true;
            masterEditor.MouseInfo.LeftButtonPreviewPoint = startCPPoint;
            draggingType = ControlDraggingType.StartCP;
            masterEditor.MouseInfo.DraggingType = PageDraggingType.MoveLineWidgetControler;

            startCPCtrl.Visibility = System.Windows.Visibility.Hidden;
        }

        public override void UpdatePointsWhenPasting(Point basePasteTopLeft)
        {
            Point newStartPoint = new Point(startPoint.X + basePasteTopLeft.X,
                startPoint.Y + basePasteTopLeft.Y);

            StartPoint = newStartPoint;

            Point newStartCPPoint = new Point(startCPPoint.X + basePasteTopLeft.X,
                startCPPoint.Y + basePasteTopLeft.Y);

            StartCPPoint = newStartCPPoint;

            Point newEndPoint = new Point(endPoint.X + basePasteTopLeft.X,
                endPoint.Y + basePasteTopLeft.Y);

            EndPoint = newEndPoint;

            Point newEndCPPoint = new Point(endCPPoint.X + basePasteTopLeft.X,
                endCPPoint.Y + basePasteTopLeft.Y);

            EndCPPoint = newEndCPPoint;
        }

        #endregion


        #region 事件=========================================================================================================


        #endregion


        #region 其它=========================================================================================================


        //public enum ControlDraggingType { Start, End, None }
        //2012年5月30日已移植并合并至Enums.LineCtrlDraggingType文件中。

        private static DoubleCollection dashArray;

        #endregion
    }
}
